package com.d2rv.experience;

import com.d2rv.guide.GoalManager;
import com.d2rv.model.CityModelManager;
import com.d2rv.offscreen.SceneGuideManager;
import com.d2rv.offscreen.SceneUserManager;
import com.d2rv.settings.FpsTimer;
import com.d2rv.settings.Settings;
import com.d2rv.skybox.SkyboxManager;
import com.d2rv.user.UserManager;
import com.d2rv.vrpn.VRPNManager;
import processing.core.PApplet;
import processing.core.PVector;

/**
 * This class contains all the main objects of the application, this is the main
 * class of the application
 *
 * @author Darrieutort A., Dupouy A., Rossignol L., Van Poucke A.
 */
public class SceneManager {

    private SceneGuideManager sceneguidemanager;
    private SceneUserManager sceneusermanager;
    private CityModelManager citymodelmanager;
    private SkyboxManager skyboxmanager;
    private GoalManager goalmanager;
    private UserManager usermanager;
    private VRPNManager vrpnmanager;
    private FpsTimer fpstimer;

    /**
     * Default constructor
     *
     * @param parent The current application
     */
    public SceneManager(PApplet parent) {
        Settings settings = Settings.getInstance();
        settings.init(parent.dataPath("settings.xml"));
        this.citymodelmanager = new CityModelManager(parent);
        this.goalmanager = new GoalManager(parent);
        this.skyboxmanager = new SkyboxManager(parent);
        this.usermanager = new UserManager(parent);
        this.sceneguidemanager = new SceneGuideManager(parent, this.usermanager, this.citymodelmanager, this.goalmanager);
        this.sceneusermanager = new SceneUserManager(parent, this.usermanager, this.citymodelmanager, this.skyboxmanager, this.goalmanager);
        this.vrpnmanager = new VRPNManager(this);
        this.fpstimer = FpsTimer.getInstance();
        this.fpstimer.init(parent);
    }

    /**
     * Calls all the draw methods for each object
     *
     * @param mode the mode of the application (0:mono 1:anaglyphe 2:side by
     * side)
     */
    public void draw(int mode) {
        this.vrpnmanager.updateVRPN();
        this.sceneguidemanager.draw();
        this.sceneusermanager.draw(mode);
        this.fpstimer.computeFps();
        this.fpstimer.previoustime(this.fpstimer.parent().millis());
    }

    /**
     * Displays the content of the different offscreen of the application
     *
     * @param parent The current application
     * @param mode the mode of the application (0:mono 1:anaglyphe 2:side by
     * side)
     */
    public void show(PApplet parent, int mode) {
        this.sceneguidemanager.show(parent);
        this.sceneusermanager.show(parent, mode);
    }

    /**
     * Returns the object UserManager
     *
     * @return the userManager
     */
    public UserManager usermanager() {
        return this.usermanager;
    }

    /**
     * Returns the object ObjectiveManager
     *
     * @return the goalManager
     */
    public GoalManager goalmanager() {
        return this.goalmanager;
    }

    /**
     * Returns the object SceneGuideManager
     *
     * @return the sceneguidemanager
     */
    public SceneGuideManager sceneguidemanager() {
        return this.sceneguidemanager;
    }
    
    /**
     * Returns the object SceneUserManager
     *
     * @return the sceneusermanager
     */
    public SceneUserManager sceneusermanager() {
        return this.sceneusermanager;
    }

    /**
     * Sets the value of the objective position 
     * @param mouseX the x coordinate of the mouse
     * @param mouseY the y coordinate of the mouse
     */
    public void setCurrentGoalPosition(float mouseX, float mouseY) {
        this.goalmanager.setCurrentGoalPosition(this.usermanager.user(), mouseX, mouseY, this.sceneguidemanager.offscreenguidemanager().zoomCameraGuide());
    }

    /**
     * Moves the user position with the coordinates of the vector move
     * @param move The vector move
     */
    public void moveUser(PVector move) {
        this.usermanager.move(PVector.mult(move, this.fpstimer.coeffps()), this.goalmanager.currentGoal());
    }

    /**
     * Moves the user head position with the coordinates of the vector move
     * @param move The vector move
     */
    public void moveUserHead(PVector move) {
        this.usermanager.moveHead(move);
    }

    /**
     * Decides in which direction the instruction arrow will be drawn
     * @param direction the different direction (0:Left 1:Right 2:Up 3:Down
     */
    public void instructionArrowDirection(int direction) {
        this.usermanager.instructionmanager().instructionInit(direction);
    }
   /**
     * Triggers the rotation of the user with an angle angle
     * @param angle the angle of the rotation
     */
    public void rotateUser(float angle) {
        this.usermanager.rotation(angle * this.fpstimer.coeffps());
    }
    
    /**
     * Progressive turn back of the user
     */
    public void rotateUserTurnBack() {
        this.usermanager.anglerotate(180);
    }
    
    /**
     * Uses to activate and desactivate head-tracking.
     * 
     * @param headtracking activates/desactivates head-tracking
     */
    public void updateHeadTracking(boolean headtracking){
        this.vrpnmanager.headtracking(headtracking);
        if(!headtracking){
            this.usermanager.user().headposition(this.usermanager.user().position());
        }
    }
    
    /**
     * Resets the application and the GUI.
     */
    public void reset(){
        this.goalmanager.mode(0);
        this.usermanager.user().position(new PVector(-Settings.getInstance().userrecoil(),0,0));
        this.usermanager.user().headposition(this.usermanager.user().position());
        this.usermanager.user().target(new PVector(-10000,0,0));
        this.usermanager.user().rotate(0);
        updateHeadTracking(false);
        this.sceneguidemanager.offscreenguidemanager().offscreenguidegui().guidegui().reset();
    }
}